<?php
/**
 * Created by PhpStorm.
 * User: Mysic
 * Date: 2020/12/24
 * Time: 11:33
 */

namespace app\common\mysic\profitShare;


use app\common\model\dealer\Capital;
use app\common\model\user\BalanceLog;
use app\common\mysic\exceptions\EntityErrorException;
use app\common\mysic\MysicBase;
use app\common\mysic\profitShare\procedures\ConditionJudgment;
use app\common\mysic\profitShare\procedures\DbData;
use app\common\mysic\profitShare\procedures\ProfitOrder;
use app\common\mysic\profitShare\procedures\ProfitShare;
use app\common\mysic\profitShare\procedures\Receives;
use app\common\mysic\profitShare\procedures\RuntimeVariables;
use think\Exception;

class Logics extends MysicBase
{
    public $conditionJudgment;
    public $profitShare;
    public $dbData;
    public $receives;
    public $profitOrder;

    public function __construct(DbData $dbData, ConditionJudgment $conditionJudgment, ProfitShare $profitShare, Receives $receives, ProfitOrder $profitOrder)
    {
        parent::__construct();
        $this->dbData = $dbData;
        $this->conditionJudgment = $conditionJudgment;
        $this->profitShare = $profitShare;
        $this->receives = $receives;
        $this->profitOrder = $profitOrder;
    }
    //订单不分账，完结分账
    public function finishOrderProfitSharing(): bool
    {
        return $this->profitShare->finishProfitSharing($this->dbData->getUserOrderEntity());
    }
    //升级用户为微股东
    public function userUpgrade()
    {
        $this->log->info('开始', '用户升级为微股东');
        $ret = true;
        $userEntity = $this->dbData->getUserEntity();
        if(0 == $userEntity->shareholder) {
            $userEntity->shareholder = 1;
            $ret = $userEntity->save();
        }
        return $ret;
    }
    //创建订单分红信息
    public function createReceive()
    {
        return $this->receives->create(
            $this->dbData->getUserOrderEntity(),
            $this->dbData->getWxSettingEntity(),
            $this->dbData->getUserEntity(),
            RuntimeVariables::getProfitUpperLimit()
        );
    }
    //订单退款方式分红
    public function orderRefund(): bool
    {
        RuntimeVariables::setBonusType(ProfitShare::BONUS_REFUND);
        RuntimeVariables::createProfitShareSn(true);
        $outRefundNo = RuntimeVariables::getProfitShareSn();
        $this->log->info($outRefundNo, '调用微信退款接口生成退款申请专号');
        $refundMoney = RuntimeVariables::getProfit();
        $orderRefundApplyResult = $this->profitShare->orderRefundApply($this->dbData->getUserOrderEntity(), $this->dbData->getWxApiConfigEntity(), $refundMoney, $outRefundNo);
        if(!$orderRefundApplyResult) {
            return false;
        }
        $orderRefundQueryResult = $this->profitShare->orderRefundQuery($this->dbData->getUserOrderEntity(), $refundMoney);
        if(!$orderRefundQueryResult) {
            return false;
        }
        return true;
    }
    //更新订单分红信息状态
    public function updateReceives(): bool
    {
        $receivesEntities = RuntimeVariables::getReceivesEntities();
        $receivesLogEntities = RuntimeVariables::getReceivesLogEntities();
        array_walk($receivesEntities, function($receivesEntity) use ($receivesLogEntities) {
            $isFinished = $this->receives->isFinished($receivesEntity->top_limit, $receivesLogEntities[$receivesEntity->order_no]->refund_fee, $receivesEntity->balance, $receivesEntity->finish_time);
            $receivesEntity->type = $isFinished;
        });
        return $this->receives->receivesUpdate($receivesEntities, $receivesLogEntities);
    }
    // 创建分红流水明细
    public function createReceivesLog($apiType = ProfitShare::API_TYPE_PROFIT_SHARING): bool
    {
        $receivesEntities = RuntimeVariables::getReceivesEntities();
        if(empty($receivesEntities)) {
            $this->log->error('未获取到订单分红信息','创建分红流水明细错误');
            return false;
        }
        $profit = RuntimeVariables::getProfit();
        $this->log->info($profit, '分红金额');
        //分红余额小于分红金额时，分红金额与余额的差额账面上要返还给商户
        $receivesEntitiesProfitMap = [];
        foreach($receivesEntities as $receivesEntity) {
            $receivesEntitiesProfitMap[$receivesEntity->order_no] = $profit;
            if(bccomp($receivesEntity->balance, $profit, 2) < 0) {
                $receivesEntitiesProfitMap[$receivesEntity->order_no] = $receivesEntity->balance;
                $exceptBalance = bcsub(strval($profit), strval($receivesEntity->balance), 2);
                $this->profitOrder->returnExceptBalanceToStore($receivesEntity->order_no, $exceptBalance);
            }
        }
        $this->log->info($receivesEntitiesProfitMap, '创建分红流水明细 - 分红订单与分红金额对应关系');
        $paidOrderNo = $this->dbData->getUserOrderEntity()->order_no ?? '';
        $paidOrderPayPrice = $this->dbData->getUserOrderEntity()->pay_price ?? '';
        return $this->receives->createReceivesLog($receivesEntities, $paidOrderNo, $paidOrderPayPrice, $receivesEntitiesProfitMap, $apiType);
    }
    //更新分红流水明细
    public function updateReceivesLog(): bool
    {
        $receivesEntities = RuntimeVariables::getReceivesEntities();
        $receivesLogEntities = RuntimeVariables::getReceivesLogEntities();
        array_walk($receivesEntities, function($receivesEntity) use (&$receivesLogEntities) {
            $receivesLogEntities[$receivesEntity->order_no]->profit_sharing_sn = RuntimeVariables::getProfitShareSn();
        });
        $applyResponse = RuntimeVariables::getWxProfitSharingApplyResponse();
        $bonusType = RuntimeVariables::getBonusType();
        $orderNo = $this->dbData->getUserOrderEntity()->order_no;
        return $this->receives->updateReceivesLog($receivesEntities, $receivesLogEntities, $orderNo, $bonusType, $applyResponse['profit_id']);
    }
    //创建平台 & 服务商分账流水单
    public function createSystemServiceProfitOrders()
    {
        try {
            return $this->profitOrder->createSystemServiceProfitOrders(
                $this->dbData->getUserOrderEntity(),
                $this->dbData->getAgentArray(),
                $this->dbData->getWxSettingEntity()->periods_num,
                $this->dbData->getSystemSetting(),
                $this->dbData->getWxAppEntity()
            );
        } catch (Exception $e) {
            $this->log->error(exceptionLogFormat($e), '创建平台&服务商分账流水单时异常');
            return false;
        }
    }
    //创建商户分账流水单
    public function createStoreProfitOrder()
    {
        try {
            return $this->profitOrder->createStoreProfitOrder(
                $this->dbData->getWxAppEntity(),
                $this->dbData->getUserOrderEntity(),
                RuntimeVariables::getProfitAmount(),
                $this->dbData->getWxSettingEntity()->periods_num
            );
        } catch (EntityErrorException $e) {
            $this->log->error(exceptionLogFormat($e), '创建商户分账流水单时异常');
            return false;
        }
    }
    //用户分红已到期，分红余额转零钱
    public function profitShareBalanceToWallet()
    {
        $this->log->info('开始', '判断用户分红是否已到期，分红余额转零钱');
        $receivesEntities = $this->dbData->getReceivesEntities();
        $receivesLogEntities = $this->dbData->getReceivesLogEntities();
        $wxSettingEntity = $this->dbData->getWxSettingEntity();
        $userEntities = $this->dbData->getUserEntities();
        $finishedReceives = $validReceivesEntities = [];

        foreach($receivesEntities as $receivesEntity) {
            $this->log->info([
                '订单号' => $receivesEntity->order_no,
                '分红是否过期' => bool2str($receivesEntity->finish_time <= time()),
                '是否转零钱' => bool2str($wxSettingEntity->moneypercentstatus)
            ],'分红是否过期，分红余额是否转零钱');
            if($receivesEntity->finish_time <= time() && $wxSettingEntity->moneypercentstatus == 1) {
                //计算用户账户零钱加上分红余额后的结余
                $balance = bcadd($userEntities[$receivesEntity->user_id]->balance, $receivesEntity->balance, 2);
                //插入零钱流水表
                BalanceLog::add(50, [
                    'user_id' => $receivesEntity->user_id,
                    'money' => $receivesEntity->balance,
                    'wxapp_id' => $receivesEntity->wxapp_id
                ],['order_no' => $receivesEntity->order_no]);
                $this->log->info(['user_id' => $receivesEntity->user_id, 'money' => $receivesEntity->balance, 'wxapp_id' => $receivesEntity->wxapp_id], '用户分红已到期，分红余额转零钱');
                //更新用户账户零钱
                $userEntities[$receivesEntity->user_id]->balance = $balance;
                $userEntities[$receivesEntity->user_id]->isUpdate()->save();
                //分红信息状态设置为不分红
                $receivesEntity->type = 1;
                $finishedReceives[$receivesEntity->order_no] = $receivesEntity;
            } else {
                $validReceivesEntities[$receivesEntity->order_no] = $receivesEntity;
            }
        }
        RuntimeVariables::setReceivesEntities($validReceivesEntities);
        if($finishedReceives) {
            RuntimeVariables::setFinishedReceivesEntities($finishedReceives);
            //更新分红信息表为已完结，分红次数增加1次
            $this->receives->receivesUpdate($finishedReceives, $receivesLogEntities);
            //更新分红流水信息表分红类型为零钱，及分红状态
            $paidOrderEntity = $this->dbData->getUserOrderEntity();
            $this->receives->updateReceivesLog($finishedReceives, $receivesLogEntities, $paidOrderEntity->order_no, ProfitShare::BONUS_BALANCE);
        }
    }
    // 判断分红次数是否到1000次，到了后转赏金
    public function profitSharingToReward(): bool
    {
        $this->log->info('开始', '判断分红次数是否到1000次，到了后转赏金');
        $dealUserCapitalModel = new Capital();
        $rewardReceives = $validReceivesEntities = $dealUserIds = [];
        $receivesEntities = RuntimeVariables::getReceivesEntities();
        $receivesLogEntities = $this->dbData->getReceivesLogEntities();
        foreach($receivesEntities as $receivesEntity) {
            if($receivesEntity->times >= 1000) {
                try {
                    $this->dbData->initDealerEntity($receivesEntity->user_id);
                    $dealUserEntity = $this->dbData->getDealerEntity();
                } catch (EntityErrorException $e) {
                    $this->log->error(exceptionLogFormat($e), '分红次数达到1000次转赏金时抛出异常');
                    continue;
                }
                $dealUserEntity->money = bcadd($dealUserEntity->money, RuntimeVariables::getProfit(), 2);
                $dealUserEntity->isUpdate(true)->save();
                $dealUserCapitalModel->data([
                    'wxapp_id'  => $dealUserEntity->wxapp_id,
                    'user_id'   => $dealUserEntity->user_id,
                    'flow_type' => 30,
                    'money'     => RuntimeVariables::getProfit(),
                    'describe'  => '分红转换'
                ])->isUpdate(false)->save();
                $rewardReceives[$receivesEntity->order_no] = $receivesEntity;
            } else {
                $validReceivesEntities[$receivesEntity->order_no] = $receivesEntity;
            }
        }
        RuntimeVariables::setReceivesEntities($validReceivesEntities);
        if($rewardReceives) {
            //更新分红信息表为已完结，分红次数增加1次
            $this->receives->receivesUpdate($rewardReceives, $receivesLogEntities);
            //更新分红流水信息表分红类型为零钱，及分红状态
            $paidOrderEntity = $this->dbData->getUserOrderEntity();
            return $this->receives->updateReceivesLog($rewardReceives, $receivesLogEntities, $paidOrderEntity->order_no, ProfitShare::BONUS_REWARD);
        }
        return true;
    }
    //用户正常分红
    public function profitSharing(): bool
    {
        $this->log->info('开始', '正常分账');
        $this->log->info('ProfitShare::BONUS_REFUND', '设置分账类型');
        RuntimeVariables::setBonusType(ProfitShare::BONUS_REFUND);
        $profitSharingReceivers = RuntimeVariables::getProfitSharingReceivers();
        $this->log->info($profitSharingReceivers, '获取分账接收人列表');
        $userEntities = $this->dbData->getUserEntities();
        $receivesEntities = $this->dbData->getReceivesEntities();
        $this->profitShare->addProfitSharingReceivers($receivesEntities, $userEntities);
        $paidOrderEntity = $this->dbData->getUserOrderEntity();
        $profitSharingSn = RuntimeVariables::createProfitShareSn();
        $profitSharingResult = $this->profitShare->profitSharingApply($profitSharingReceivers, $profitSharingSn, $paidOrderEntity->transaction_id);
        if(!$profitSharingResult) {
            return false;
        }
        return $this->profitShare->profitSharingQuery(RuntimeVariables::getProfitShareSn(), $paidOrderEntity->transaction_id);
    }
    //删除分账接收人
    public function removeReceivers(): bool
    {
        $this->log->info('开始', '删除分账接收人');
        $receivesEntities = RuntimeVariables::getFinishedReceivesEntities();
        return $this->profitShare->removeProfitSharingReceivers($receivesEntities);
    }
    //更新平台分账流水单状态
    public function updateSystemProfitOrder(): bool
    {
        $this->log->info('开始', '更新平台分账流水单状态');
        $entity = RuntimeVariables::getSystemProfitOrderEntity();
        return $this->profitOrder->updateSystemProfitOrder($entity);
    }
    //更新服务商分账流水单状态
    public function updateServiceProfitOrder(): bool
    {
        $this->log->info('开始', '更新服务商分账流水单状态');
        $entities = RuntimeVariables::getServiceProfitOrderEntities();
        return $this->profitOrder->updateServiceProfitOrder($entities);
    }
    //更新商户分账流水单状态
    public function updateStoreProfitOrder(): bool
    {
        $this->log->info('开始', '更新商户分账流水单状态 ');
        $entity = RuntimeVariables::getStoreProfitOrderEntity();
        return $this->profitOrder->updateStoreProfitOrder($entity);
    }

    public function makeProfitSharingMessages(): array
    {
        $otherReceivesEntities = RuntimeVariables::getReceivesEntities();
        $userOrderEntity = $this->dbData->getUserOrderEntity();
        $receivesOrders = [];
        $usersDuplicationSet = [];
        foreach ($otherReceivesEntities as $entity) {
            $usersDuplicationSet[] = $entity->user_id;
            $receivesOrders[$entity->user_id][] = $entity->order_no;
        }
        $usersDuplicationSet = array_count_values($usersDuplicationSet);
        arsort($usersDuplicationSet);
        $normalUserIds = $dupUserIds = [];
        foreach($usersDuplicationSet as $userId => $count) {
            if(1 == $count) {
                $normalUserIds[] = $userId;
                continue;
            }
            $dupUserIds[] = $userId;
        }
        $singleReceivesOrderNos = [];
        foreach($normalUserIds as $userId) {
            $singleReceivesOrderNos[] = $receivesOrders[$userId][0];
        }
        $page = 1;
        $seqCount = 0;
        if($dupUserIds) {
            $totalPage = ceil((count($singleReceivesOrderNos)) / 50) >= count($receivesOrders[$dupUserIds[0]]) ? ceil((count($singleReceivesOrderNos)) / 50) : count($receivesOrders[$dupUserIds[0]]);
        }else {
            $totalPage = ceil((count($singleReceivesOrderNos)) / 50);
        }

        $mqMsg = [];
        $addedOrderNos = [];
        while($page <= $totalPage) {
            if($page == 1) {
                $mqMsg[$page][] = 'SYSTEM_PROFIT_SHARING';
            }
            foreach($dupUserIds as $userId) {
                $key = $page - 1;
                if(key_exists($key, $receivesOrders[$userId])) {
                    $mqMsg[$page][] = $receivesOrders[$userId][$key];
                    $seqCount++;
                }
                if($seqCount == 50) {
                    break;
                }
            }
            if($seqCount == 50) {
                $page++;
                continue;
            }
            $lastOrderNos = $singleReceivesOrderNos;
            foreach($lastOrderNos as $orderNo) {
                $mqMsg[$page][] = $orderNo;
                $addedOrderNos[] = $orderNo;
                $seqCount++;
                if($seqCount == 50) {
                    break;
                }
            }
            $singleReceivesOrderNos = array_diff($lastOrderNos, $addedOrderNos);
            $addedOrderNos = [];
            $page++;
        }
        $messages = [];
        foreach ($mqMsg as $page => $orderNos) {
            $finishProfitSharing = 0;
            if ($page == $totalPage) {
                $finishProfitSharing = 1;
            }
            $msg = [
                'order_no'              => $userOrderEntity->order_no,
                'receives_order_no'     => $orderNos,
                'finish_profit_sharing' => $finishProfitSharing // 完结分账 finish_profit_sharing = 1 完结 | 0 不完结
            ];
            $messages[] = $msg;
        }
        return $messages;
    }
}